查看原文
其他

MIPS缓冲区溢出学习

蓝色淡风 看雪学院 2019-05-26


前言

之前在学习家用路由器这本书以及看网上大佬写相关文章的时候,总感觉有些关键细节一笔带过,有时候给我造成了很大的困扰,鉴于这个原因,我想到把自己的一些思考以及实际操作经验写出来给后来者,希望他们不要再走我走过的弯路。


引爆内存崩溃

首先看源代码:

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

void do_system(int code,char *cmd)
{
   char buf[255];
   //sleep(1);
   system(cmd);
}

void main()
{
   char buf[256]={0};
   char ch;
   int count = 0;
   unsigned int fileLen = 0;
   struct stat fileData;
   FILE *fp;

   if(0 == stat("passwd",&fileData))
       fileLen = fileData.st_size;
   else
       return 1;

   if((fp = fopen("passwd","rb")) == NULL)
   {
       printf("Cannot open file passwd!n");
       exit(1);
   }


   ch=fgetc(fp);
   while(count <= fileLen)
   {
       buf[count++] = ch;
       ch = fgetc(fp);
   }
   buf[--count] = 'x00';

   if(!strcmp(buf,"adminpwd"))
   {
       do_system(count,"ls -l");
   }
   else
   {
       printf("you have an invalid password!n");
   }
   fclose(fp);
}

将vuln_system.c 拷贝至对应目录下:

执行如下命令:

root@ricard-virtual-machine:~/my_file# /root/my_file/buildroot1/buildroot/output/host/bin/mips-linux-gcc vuln_system.c -static -o vuln_system

root@ricard-virtual-machine:~/my_file# python -c "print 'A'*600">passwd

root@ricard-virtual-machine:~/my_file# qemu-mips vuln_system

而后会出现错误:

程序引发了一段故障,使用如下命令重新执行:

root@ricard-virtual-machine:~/my_file# qemu-mips vuln_system `python -c "print 'A'*600"`

这里直接运行,发生崩溃就退出了;

加-g是等待调试的:

root@ricard-virtual-machine:~/my_file# qemu-mips -g 1234 ./vuln_system `python -c "print 'A'*600"`

执行完这条指令之后,使用IDA进行附加调试:


这里选择大端是因为这个文件是mips大端格式的。



附加之后,在IDA里面按F9键(书里面写的是F5,这是错的!)可以看到程序在试图执行0x41414141的时候崩溃了,如下图所示:



这是因为0x41414141将原来的返回地址给覆盖了,程序在返回的时候返回的是0x41414141这个无效地址而不是原来的地址,故会崩溃。


劫持流程


计算偏移


通过阅读vuln_system.c的源码可以知道,main函数里面,在读取完passwd这个文件之后,将passwd文件里面的所有数据存入堆栈的局部变量buf里面,而buf的大小仅为256字节,而passwd文件有600字节大小的数据写入buf,导致了缓冲区溢出。


通过静态分析发现,如果要使缓冲区溢出,并控制到堆栈中的返回地址saved_ra,需要覆盖的数据大小应该达到0x1A0-0x04即0x19c字节;作者这里运用这个公式的依据是什么呢?让我们回顾一下X86架构下的情形:


偏移不就是找buf和ra之间的偏移么,ra是存储于栈里面的(有点类似于x86里面的ret指令),buf指向栈里面,只要计算出buf的初始位置和ra之间的偏移,就可以计算出有多少个字节就可以溢出到ra了!


寻找偏移


上图是主函数里面的一开始的部分,为了进一步分析出偏移,笔者将相关汇编指令誊写并注释如下:

addiu   $sp, -0x1D0            //sp <==sp-0x1D0
  sw      $ra, 0x1D0+var_4($sp)    //将ra里面的值存放于堆栈里面,其偏移值为0x1D0+var_4
 sw      $fp, 0x1D0+var_8($sp)        //将fp里面的值存放于堆栈里面,其偏移为0x1D0+var_8
 move    $fp, $sp                    //fp<== sp

 li      $gp, 0x4291A0                //li指令:将一个立即数存放于寄存器里面
 sw      $gp, 0x1D0+var_1C0($sp)    //将gp里面的值存放于堆栈里面,其偏移为0x1D0+var_1C0
 addiu   $v0, $fp, 0x1D0+var_1A0    //v0用于存放函数函数返回值
 li      $v0, 0x100                //将立即数0x100传入v0
 move    $a2, $v1                    //MIPS架构中一般使用a0-a3作为函数的前4个参数
 move    $a1, $zero                //zero寄存器里面永远为0
 move    $a0, $v0                    //a0=v0
 la      $v0, memset                //复制memset地址至至v0中
 move    $t9, $v0                    //$t0-$t9供汇编程序使用的临时变量
 bal     memset                    //无条件转移,并且将转移指令后面的第二条地址作为返回值存放于Ra里面
 nop

结合源代码看,可以发现主函数里面调用的第一个函数为memset函数,貌似源代码里面没有这个函数,怎么回事?

继续看,发现在调用这个函数之前是调用了3个参数的,分别用到a0、a1、和a2这几个寄存器(在MIPS架构里面,是用a0-a3这几个寄存器来传参的)。

而函数memset的原型为void* memset(void* s,int ch,unsigned n),其主要功能为:在内存空间里以s为起始的地方,将开始的n个字节设为指定值;可以发现传给a2的值为v1,而传给$v1的为0x100(0x100实际上就是十进制256)。

分析到这里,大家应该会清晰了吧。这里在做的事情其实是内存初始化,通过这个函数将内存里面的256个字节初始化为0,而这里的内存初始地址是通过指令addiu $v0,$fp,0x1D0+var_1A0来确定的。显然,0x1D0+var_1A0就是我们要找的buf的起始偏移,到这里,我们才能确定:需要覆盖的数据大小应该为0x1D0+var_1A0-0x1D0-var_4即0x19c字节。


验证

root@ricard-virtual-machine:~/my_file# python -c "print 'A'*0x19c + 'BBBB'+'CCCC'">passwd

root@ricard-virtual-machine:~/my_file# qemu-mips -g 1234 vuln_system

输入指令之后,程序就会处于等待调试的状态;而后利用IDA附加该进程(此过程在前面已经叙述过)。

由于这里使用附加调试的效果不是太好,我这里使用的运行时调试的方法,读者可以参考这本书即可。

在主函数结尾的地方下断点,按F9运行程序,会在0x004006CC这个地址断下。

双击0x004006D0这行,来到返回地址在栈空间0x40800104(也可以利用SP+0x1D0+VAR_4得到)处,如下图所示:

查看HEX VIEW-1窗口,发现返回地址已经被覆盖为0x42424242,如下图所示。

此时缓冲区已经被输入的数据所覆盖,并且越界后覆盖了堆栈上的其他数据。

继续按F8键执行指令jr $ra,程序就会跳往0x42424242出执行,如下图所示:


小结


在这一节里面,主要学习的知识点是如何计算偏移达到覆盖返回地址的目的,这里总结出一个公式:

偏移=函数返回地址-缓冲区首地址

(注:在堆栈中,一般函数返回地址处于高地址,缓冲区地址处于低地址),今天就暂时写到这里,后面有时间我会带来更多的分享。

最后夸一夸看雪的markdown,用户体验特别好!!!



看雪ID:蓝色淡风

bbs.pediy.com/user-723202



本文由看雪论坛 蓝色淡风 原创

转载请注明来自看雪社区





热门技术文章推荐:





戳原文,看看大家都是怎么说的?

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存